package utils

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
)

// HttpGet HTTP Get 请求，并解析响应数据到 result 中
func HttpGet(url string, headers map[string]string, result interface{}) error {
	// 构造请求
	client := &http.Client{}
	req, err := http.NewRequest(http.MethodGet, url, nil)
	if err != nil {
		fmt.Println(err.Error())
		return err
	}
	req.Header.Set("Content-Type", "application/json")
	for k, v := range headers {
		req.Header.Set(k, v)
	}

	// 请求
	resp, err := client.Do(req)
	if err != nil {
		fmt.Println(err.Error())
		return err
	}

	defer resp.Body.Close()

	//  读取并解析数据
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return err
	}
	return json.Unmarshal(body, result)
}

// HttpPostJson HTTP Post json请求，并解析响应的数据到 result 中
// data 为可 json 序列化的参数数据
// result 为响应要解析的对象
func HttpPostJson(method string, url string, data any, headers map[string]string, result interface{}) error {
	client := &http.Client{}
	// 请求的数据进行序列化
	params, err := json.Marshal(data)
	if err != nil {
		return err
	}
	req, err := http.NewRequest(method, url, bytes.NewBuffer(params))
	if err != nil {
		return err
	}
	req.Header.Set("Content-Type", "application/json")
	for k, v := range headers {
		req.Header.Set(k, v)
	}

	// 请求
	resp, err := client.Do(req)
	if err != nil {
		return err
	}

	defer resp.Body.Close()
	// 解析响应数据
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return err
	}
	return json.Unmarshal(body, result)
}

// DownloadFile 从 url 下载文件并保存到 localPath
func DownloadFile(url, localPath string) error {
	client := &http.Client{}
	req, err := http.NewRequest(http.MethodGet, url, nil)
	if err != nil {
		return err
	}
	resp, err := client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	f, err := os.OpenFile(localPath, os.O_CREATE|os.O_RDWR, 0666)
	if err != nil {
		return err
	}
	// 分片读取，每次读取1KB，避免要下载的文件过大
	for true {
		var bytes = make([]byte, 1<<10)
		n, err := io.ReadFull(resp.Body, bytes)
		fmt.Println("downloading file, read", n)
		if err == io.EOF {
			// 读取完成
			return nil
		}
		// 写入到文件中
		_, err = f.Write(bytes)
		if err != nil {
			return err
		}
	}
	return nil
}
